﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MathMethods;
using WinAPI32Library;


namespace TestCommandLine
{
    class Program
    {
        public static double[] x, y;

        static void Main(string[] args)
        {
            ReadData();


            StreamWriter w = new StreamWriter("threads.txt", true);
            // write args to file
            string arguments = "";
            foreach (string arg in args)
                arguments += " " + arg;
            arguments = arguments.Trim();
            w.WriteLine("Arguments: " + arguments);

            // vars used in GetProcessTimes method
            long
                _creation = 0,
                _exit = 0,
                _kernel = 0,
                _user = 0;

            // thread id
            uint threadId = 0;
            // thread handle
            IntPtr thread = IntPtr.Zero;
            // methods to be execudet by thread
            Kernel32.LPTHREAD_START_ROUTINE[] methods = {
                                                            new Kernel32.LPTHREAD_START_ROUTINE(Program.Newthon),
                                                            new Kernel32.LPTHREAD_START_ROUTINE(Program.Lagrange),
                                                            new Kernel32.LPTHREAD_START_ROUTINE(Program.LeastSquaresMetod)
                                                        };
            // available thread priorities
            int[] threadPriorities = {
                                         (int)Kernel32.ThreadPriority.THREAD_PRIORITY_IDLE,
                                         (int)Kernel32.ThreadPriority.THREAD_PRIORITY_LOWEST,
                                         (int)Kernel32.ThreadPriority.THREAD_PRIORITY_BELOW_NORMAL,
                                         (int)Kernel32.ThreadPriority.THREAD_PRIORITY_NORMAL,
                                         (int)Kernel32.ThreadPriority.THREAD_PRIORITY_ABOVE_NORMAL,
                                         (int)Kernel32.ThreadPriority.THREAD_PRIORITY_HIGHEST,
                                         (int)Kernel32.ThreadPriority.THREAD_PRIORITY_TIME_CRITICAL
                                     };

            // go through all three threads to be executed
            for (int i = 0; i < 3; i++)
            {
                // create thread
                thread = Kernel32.CreateThread(0, 0, methods[i], 0, (uint)Kernel32.CreationFlags.CREATE_SUSPENDED, out threadId);
                // set thread priority
                Kernel32.SetThreadPriority(thread, threadPriorities[Convert.ToInt32(args[i])]);
                // write data to file
                w.Write("Thread priority: " + Kernel32.GetThreadPriority(thread) + "/" + threadPriorities[Convert.ToInt32(args[i])]);
                // resume thread
                Kernel32.ResumeThread(thread);
                // wait while thread will be executed
                Kernel32.WaitForSingleObject(thread, Kernel32.INFINITE);
                // get thread times
                Kernel32.GetThreadTimes((IntPtr)thread, out _creation, out _exit, out _kernel, out _user);
                // calculate thread execution time
                TimeSpan time = Kernel32.Elapsed(_creation, _exit);
                //echo("===\nElapsed: " + time.Milliseconds);
                // write thread data to file
                w.WriteLine(", thread " + i + ": " + time.Milliseconds + " ms");
                // close thread handle
                Kernel32.CloseHandle(thread);
            }
            // close file
            w.Close();
            //Console.ReadKey();
        }

        public static uint Newthon(uint lpParam)
        {
            Console.WriteLine("==========\nИнтерполяционный метод Ньютона.");
            // arguments
            double[] x_ = x;
            // values
            double[] y_ = y;
            // fill values array
            //for (int i = 0; i < x_.Length; i++)
            //    y_[i] = NumericalMethods.FunctionForNewtonPolynomial(x_[i]);
            // interpolation
            double[] xi = { 1.5, 2.5, 3.5, 4.5, 5.5 };
            double[] yi = new double[xi.Length];
            for (int i = 0; i < xi.Length; i++)
                yi[i] = NumericalMethods.NewtonPolynomial(xi[i], x_, y_);
            NumericalMethods.PrintFunctionValues(xi, yi, 3);

            //double[] yr = new double[xi.Length];
            //for (int i = 0; i < xi.Length; i++)
            //    yr[i] = NumericalMethods.FunctionForNewtonPolynomial(xi[i]);
            //NumericalMethods.PrintFunctionValues(xi, yr, 3);
            return 0;
        }

        public static uint Lagrange(uint lpParam)
        {
            Console.WriteLine("==========\nИнтерполяционный метод Лагранжа");
            double[] xi = x;
            double[] yi = y;

            Console.WriteLine("Исходные точки");
            for (int i = 0; i < xi.Length; i++)
                Console.WriteLine("y(" + xi[i] + ") = " + yi[i]);

            Console.WriteLine("Проверка метода на исходных точках");
            for (int i = 0; i < xi.Length; i++)
            {
                double res = NumericalMethods.LagrangePolynomial(xi[i], xi, yi);
                if (res == yi[i])
                    Console.WriteLine("y(" + xi[i] + ") = " + res);
            }

            Console.WriteLine("Вычисление значений в промежуточных точках");
            for (int i = 1; i < xi.Length; i++)
            {
                double transitional = (xi[i - 1] + xi[i]) / 2;
                double res = NumericalMethods.LagrangePolynomial(transitional, xi, yi);
                Console.WriteLine("y(" + transitional + ") = " + res.ToString("F3"));
            }
            return 0;
        }

        public static uint LeastSquaresMetod(uint lpParam)
        {
            Console.WriteLine("==========\nМетод наименьших квадратов.");
            // заданные пользователем точки
            double[] x = new double[100], y = new double[100];
            // считываем данные из файла
            StreamReader r = new StreamReader(@"D:\MSVSProjects\Erofeev\LeastSquares\bin\Debug\data.txt", System.Text.Encoding.UTF8);
            string s = "";
            int i = 0;
            while ((s = r.ReadLine()) != null)
            {
                x[i] = Convert.ToDouble(s.Split(' ')[0]);
                y[i] = Convert.ToDouble(s.Split(' ')[1]);
                i++;
            }
            r.Close();
            // максимальная длина
            int n = Math.Min(x.Length, y.Length);

            double
                // вычисление формулы 1
                s1 = x.Aggregate(0.0, (current, item) => current + item),
                // вычисление формулы 2
                s2 = y.Aggregate(0.0, (current, item) => current + item),
                // вычисление формулы 3
                s3 = x.Aggregate(0.0, (current, item) => current + item * item),
                s4 = 0;
            // вычисление формулы 4
            for (i = 0; i < n; i++)
                s4 += x[i] * y[i];
            // вычисление коэффициентов прямой
            double a = (s4 - (s1 * s2) / n) / (s3 - s1 * s1 / n),
                   b = (s2 - a * s1) / n;
            // вывод данных
            echo("a = " + a);
            echo("b = " + b);

            echo("Write the argument: ", false);
            // ввод аргумента и вычисление функции
            double
                //arg = Convert.ToDouble(Console.ReadLine()),
                arg = 9,
                func = a * arg + b;
            echo(arg);
            echo(func);

            return 0;
        }

        public static void ReadData()
        {
            // считываем данные из файла
            StreamReader r = new StreamReader(@"D:\MSVSProjects\Erofeev\LeastSquares\bin\Debug\data.txt", System.Text.Encoding.UTF8);
            string s = "";
            List<double> xtemp = new List<double>();
            List<double> ytemp = new List<double>();

            while ((s = r.ReadLine()) != null)
            {
                xtemp.Add(Convert.ToDouble(s.Split(' ')[0]));
                ytemp.Add(Convert.ToDouble(s.Split(' ')[1]));
            }
            r.Close();
            x = xtemp.ToArray();
            y = ytemp.ToArray();
        }

        public static void echo(dynamic s, bool newline = true)
        {
            if (newline)
                Console.WriteLine(s);
            else
                Console.Write(s);
        }
    }
}

